package com.hangim.pce.controller;

import com.hangim.pce.enums.PeopleType;
import com.hangim.pce.enums.RuleLevel;
import com.hangim.pce.enums.RuleTargetType;
import com.hangim.pce.enums.RuleType;
import com.hangim.pce.model.*;
import com.hangim.pce.model.vo.PatientVo;
import com.hangim.pce.model.vo.request.DrugListVo;
import com.hangim.pce.model.vo.request.SyncRecipeBody;
import com.hangim.pce.model.vo.request.SyncRecipeReqVo;
import com.hangim.pce.model.vo.response.BaseResult;
import com.hangim.pce.model.vo.response.DrugResponseVo;
import com.hangim.pce.model.vo.response.RuleVo;
import com.hangim.pce.model.vo.response.SyncRecipeResVo;
import com.hangim.pce.service.*;
import com.baomidou.mybatisplus.plugins.Page;
import com.github.pig.common.constant.CommonConstant;
import com.github.pig.common.util.Query;
import com.github.pig.common.util.R;
import com.github.pig.common.web.BaseController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author hongjiliang
 * @since 2018-10-19
 */
@RestController
@RequestMapping("/medPrescription")
public class MedPrescriptionController extends BaseController {

    @Autowired
    private MedPrescriptionService medPrescriptionService;

    @Autowired
    private SysDrugRuleService sysDrugRuleService;

    @Autowired
    private SysElementRuleService sysElementRuleService;

    @Autowired
    private SysDrugUsageRuleService sysDrugUsageRuleService;

    @Autowired
    BaseDrugElementService baseDrugElementService;

    @Autowired
    BaseDrugService baseDrugService;

    @Autowired
    SysPrescriptionService sysPrescriptionService;

    @Autowired
    SysPrescriptionDetailService sysPrescriptionDetailService;

    @Autowired
    SysPrescriptionDetailRuleService sysPrescriptionDetailRuleService;

    /**
     * 通过ID查询
     *
     * @param id ID
     * @return MedPrescription
     */
    @GetMapping("/{id}")
    public R<MedPrescription> get(@PathVariable Long id) {
        return new R<>(medPrescriptionService.selectById(id));
    }


    /**
     * 分页查询信息
     *
     * @param params 分页对象
     * @return 分页对象
     */
    @RequestMapping("/page")
    public Page page(@RequestParam Map<String, Object> params) {
        params.put(CommonConstant.DEL_FLAG, CommonConstant.STATUS_NORMAL);
        return medPrescriptionService.selectPage(new Query<>(params));
    }

    /**
     * 添加
     *
     * @param medPrescription 实体
     * @return success/false
     */
    @PostMapping
    public R<Integer> add(@RequestBody MedPrescription medPrescription) {
        return new R<>(medPrescriptionService.insert(medPrescription));
    }

    /**
     * 删除
     *
     * @param id ID
     * @return success/false
     */
    @DeleteMapping("/{id}")
    public R<Integer> delete(@PathVariable Long id) {
        MedPrescription medPrescription = new MedPrescription();
        medPrescription.setId(id);
        medPrescription.setUpdatedDate(new Date());
        medPrescription.setActive(0);
        return new R<>(medPrescriptionService.updateById(medPrescription));
    }

    /**
     * 编辑
     *
     * @param medPrescription 实体
     * @return success/false
     */
    @PutMapping
    public R<Integer> edit(@RequestBody MedPrescription medPrescription) {
        medPrescription.setUpdatedDate(new Date());
        return new R<>(medPrescriptionService.updateById(medPrescription));
    }

    /**
     * 医疗机构处方流出接口
     *
     * @param syncRecipeReqVo
     * @return
     */
    @PostMapping("/syncRecipe")
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public BaseResult syncRecipe(@RequestBody SyncRecipeReqVo syncRecipeReqVo) throws Exception {
        Assert.notNull(syncRecipeReqVo.getHeader(), "header不能为空");
        SyncRecipeBody syncRecipeBody = syncRecipeReqVo.getBody();
        Assert.notNull(syncRecipeBody.getRecipeStatus(), "参数recipeStatus不能为空");
        Assert.hasText(syncRecipeBody.getUserAccount(), "参数userAccount不能为空");
        Assert.hasText(syncRecipeBody.getUserName(), "参数userName不能为空");
        Assert.hasText(syncRecipeBody.getUserSfzh(), "参数userSfzh不能为空");
        Assert.hasText(syncRecipeBody.getUserSex(), "参数userSex不能为空");
        Assert.notNull(syncRecipeBody.getUserAge(), "参数userAge不能为空");
        Assert.hasText(syncRecipeBody.getDiagnoseDetail(), "参数diagnoseDetail不能为空");
        Assert.hasText(syncRecipeBody.getRecipeType(), "参数recipeType不能为空");
        Assert.notNull(syncRecipeBody.getDrugList(), "参数drugList不能为空");
        List<DrugListVo> drugList = syncRecipeBody.getDrugList();
        drugList.forEach(drugListVo -> {
            Assert.hasText(drugListVo.getDrugName(), "药品名称不能为空");
            Assert.hasText(drugListVo.getDose(), "药品：" + drugListVo.getDrugName() + "参数dose不能为空");
            Assert.hasText(drugListVo.getDoseUnit(), "药品：" + drugListVo.getDrugName() + "参数doseUnit不能为空");
            Assert.hasText(drugListVo.getFreq(), "药品：" + drugListVo.getDrugName() + "参数freq不能为空");
            Assert.hasText(drugListVo.getFreqUnit(), "药品：" + drugListVo.getDrugName() + "参数freqUnit不能为空");
            Assert.hasText(drugListVo.getUseage(), "药品：" + drugListVo.getDrugName() + "参数useage不能为空");
            Assert.hasText(drugListVo.getCount(), "药品：" + drugListVo.getDrugName() + "参数count不能为空");
            Assert.hasText(drugListVo.getCountUnit(), "药品：" + drugListVo.getDrugName() + "参数countUnit不能为空");
            Assert.hasText(drugListVo.getNorms(), "药品：" + drugListVo.getDrugName() + "参数norms不能为空");
        });

        //初始化返回结果
        SyncRecipeResVo syncRecipeResVo = new SyncRecipeResVo();
        //获取患者人群
        PatientVo patientVo = getPatientVo(syncRecipeBody);

        //处方不触发规则时为1
        int result = 1;
        //药品Id
        List<Long> drugIds = new ArrayList<>();
        //药品名称数组
        List<String> drugNames = new ArrayList<>();
        //药品成分Id
        List<Long> elementIds = new ArrayList<>();
        //药品成分名称
        List<String> elementNames = new ArrayList<>();
        for (DrugListVo drugListVo : drugList) {
            //暂时直接获取数据库对应药品Id
            BaseDrug condition = new BaseDrug();
            condition.setName(drugListVo.getDrugName());
            //难以确保基本药品表无重复数据 必须是药品库里面有的药品
            List<BaseDrug> drugs = baseDrugService.selectAll(condition);
            if (drugs != null && drugs.size() >= 1) {
                drugListVo.setDrugId(drugs.get(0).getId());
                drugListVo.setActive(true);
                //获取药品成分
                List<BaseDrugElement> drugElements = baseDrugElementService.selectByDrugId(drugListVo.getDrugId());
                for (BaseDrugElement drugElement : drugElements) {
                    elementNames.add(drugElement.getElementName());
                    elementIds.add(drugElement.getElementId());
                }
                drugNames.add(drugListVo.getDrugName());
                drugIds.add(drugListVo.getDrugId());
            } else {
                //药品库中找不到药品
                drugListVo.setActive(false);
            }

        }

        //将请求存入来源表MQ
        //存入处方表
        SysPrescription prescription = sysPrescriptionService.savePrescription(syncRecipeBody, patientVo);

        //存入处方明细表
        sysPrescriptionDetailService.savePrescriptionDetail(drugList, prescription);

        //处理基本信息出错
        List<RuleVo> ruleList = new ArrayList<>();

        if (drugList == null || drugList.size() == 0) {
            RuleVo vo = new RuleVo();
            vo.setName("没有药品");
            vo.setDescription("处方不能没有药品");
            result = -1;
            ruleList.add(vo);
        } else if (drugList.size() >= 6) {
            RuleVo vo = new RuleVo();
            vo.setName("药品数量过多");
            vo.setDescription("同一处方药品数量不应该超过5个");
            ruleList.add(vo);
            result = -1;
        }

        //处理药品出错
        //药品审核返回信息
        List<DrugResponseVo> drugVoList = new ArrayList<>();

        for (DrugListVo drugListVo : drugList) {
            //药品库存在的药品
            if (drugListVo.getActive()) {

                DrugResponseVo vo = new DrugResponseVo();

                List<SysElementRule> elementRules = new ArrayList<>();

                List<SysDrugRule> drugRules = new ArrayList<>();

                List<SysDrugUsageRule> drugUsageRules = new ArrayList<>();

                //成分规则
                List<SysElementRule> elementList = sysElementRuleService.getElementRulesByDrugId(drugListVo.getDrugId());
                for (SysElementRule rule : elementList) {
                    //人群
                    if (RuleType.PEOPLE.getNum().equals(rule.getType())) {
                        if ((patientVo.getPeoples().contains(rule.getName())) && (rule.getLevel().equals(1) || rule.getLevel().equals(3))) {
                            elementRules.add(rule);
                            result = -1;
                            triggerRule(rule.getId(), prescription.getId(), rule.getDescription(), RuleTargetType.ELEMENT.getNum());
                        }
                    }

                    //配偶禁忌
                    if (RuleType.COMPATE.getNum().equals(rule.getType())) {
                        if ((elementNames.contains(rule.getName())) && (rule.getLevel().equals(1) || rule.getLevel().equals(3))) {
                            elementRules.add(rule);
                            result = -1;
                            triggerRule(rule.getId(), prescription.getId(), rule.getDescription(), RuleTargetType.ELEMENT.getNum());
                        }
                    }

                    //相互作用
                    if (RuleType.INTERACTION.getNum().equals(rule.getType())) {
                        if ((elementNames.contains(rule.getName())) && (rule.getLevel().equals(1) || rule.getLevel().equals(3))) {
                            elementRules.add(rule);
                            result = -1;
                            triggerRule(rule.getId(), prescription.getId(), rule.getDescription(), RuleTargetType.ELEMENT.getNum());
                        }
                    }

                    //用法错误
                    if (RuleType.USAGE.getNum().equals(rule.getType())) {
                        if (rule.getName().equals(drugListVo.getUseage()) && (rule.getLevel().equals(1) || rule.getLevel().equals(3))) {
                            elementRules.add(rule);
                            result = -1;
                            triggerRule(rule.getId(), prescription.getId(), rule.getDescription(), RuleTargetType.ELEMENT.getNum());
                        }
                    }

                }

                //药品规则
                List<SysDrugRule> drugLists = sysDrugRuleService.getDrugRulesByDrugId(drugListVo.getDrugId());
                for (SysDrugRule rule : drugLists) {
                    //人群
                    if (RuleType.PEOPLE.getNum().equals(rule.getType())) {
                        if ((patientVo.getPeoples().contains(rule.getName())) && (rule.getLevel().equals(1) || rule.getLevel().equals(3))) {
                            drugRules.add(rule);
                            result = -1;
                            triggerRule(rule.getId(), prescription.getId(), rule.getDescription(), RuleTargetType.DRUG.getNum());
                        }
                    }

                    //配偶禁忌
                    if (RuleType.COMPATE.getNum().equals(rule.getType())) {
                        if ((drugNames.contains(rule.getName())) && (rule.getLevel().equals(1) || rule.getLevel().equals(3))) {
                            drugRules.add(rule);
                            result = -1;
                            triggerRule(rule.getId(), prescription.getId(), rule.getDescription(), RuleTargetType.DRUG.getNum());
                        }
                    }

                    //相互作用
                    if (RuleType.INTERACTION.getNum().equals(rule.getType())) {
                        if ((drugNames.contains(rule.getName())) && (rule.getLevel().equals(1) || rule.getLevel().equals(3))) {
                            drugRules.add(rule);
                            result = -1;
                            triggerRule(rule.getId(), prescription.getId(), rule.getDescription(), RuleTargetType.DRUG.getNum());
                        }
                    }

                    //用法错误
                    if (RuleType.USAGE.getNum().equals(rule.getType())) {
                        if (rule.getName().equals(drugListVo.getUseage()) && (rule.getLevel().equals(1) || rule.getLevel().equals(3))) {
                            drugRules.add(rule);
                            result = -1;
                            triggerRule(rule.getId(), prescription.getId(), rule.getDescription(), RuleTargetType.DRUG.getNum());
                        }
                    }

                    //症状匹配

                }


                //重复用药标志
                BaseDrug baseDrug = baseDrugService.selectById(drugListVo.getDrugId());
                //重复次数
                int index = 0;
                for (String name : drugNames) {
                    if (drugListVo.getDrugName().equals(name)) {
                        index++;
                    }
                }
                //重复次数大于2
                if (!baseDrug.getRepeat() && index >= 2) {
                    SysDrugRule drugRule = new SysDrugRule();
                    drugRule.setDrugName(drugListVo.getDrugName());
                    drugRule.setDrugId(drugListVo.getDrugId());
                    drugRule.setName(drugListVo.getDrugName());
                    drugRule.setLevel(RuleLevel.DISABLE.getNum());
                    drugRule.setType(RuleType.REPEAT_DOSING.getNum());
                    drugRule.setDescription(drugListVo.getDrugName() + RuleType.REPEAT_DOSING.getDesc());
                    drugRules.add(drugRule);
                    result = -1;
                    triggerRule(0L, prescription.getId(), RuleType.REPEAT_DOSING.getDesc(), RuleTargetType.DRUG.getNum());
                }

                //用法用量规则


                //药品审核返回信息
                vo.setDrugRules(drugRules);
                vo.setDrugUsageRules(drugUsageRules);
                vo.setElementRules(elementRules);

                drugVoList.add(vo);

            }


        }

        //处方审核结果
        syncRecipeResVo.setResult(String.valueOf(result));
        //返回请求结果
        syncRecipeResVo.setDrugVoList(drugVoList);

        return syncRecipeResVo;
    }


    private void triggerRule(Long id, Long preId, String description, Integer num) {
        SysPrescriptionDetailRule rule = new SysPrescriptionDetailRule();
        rule.setRuleId(id);
        rule.setType(num);
        rule.setDescription(description);
        rule.setPresId(preId);
        sysPrescriptionDetailRuleService.saveRule(rule);
    }


    private PatientVo getPatientVo(SyncRecipeBody syncRecipeBody) {
        PatientVo vo = new PatientVo();
        List<String> peoples = new ArrayList<>();
        vo.setUserSex(syncRecipeBody.getUserSex());
        vo.setBriefHistory(syncRecipeBody.getBriefHistory());
        vo.setDiagnoseDetail(syncRecipeBody.getDiagnoseDetail());

        if (syncRecipeBody.getYwgms().equalsIgnoreCase("1")) {
            peoples.add(PeopleType.HYPERTENSION.getDesc());
        }

        if (syncRecipeBody.getTsrqType().equalsIgnoreCase("1")) {
            peoples.add("孕妇");
        } else if (syncRecipeBody.getTsrqType().equalsIgnoreCase("2")) {
            peoples.add("产妇");
        } else if (syncRecipeBody.getTsrqType().equalsIgnoreCase("3")) {
            peoples.add("哺乳");
        }

        if (syncRecipeBody.getGgnbq().equalsIgnoreCase("1")) {
            peoples.add("肝功能不全");
        }

        if (syncRecipeBody.getSgnbq().equalsIgnoreCase("1")) {
            peoples.add("肾功能不全");
        }

        if (syncRecipeBody.getGxybs().equalsIgnoreCase("1")) {
            peoples.add("高血压");
        }

        if (syncRecipeBody.getTnbs().equalsIgnoreCase("1")) {
            peoples.add("糖尿病");
        }

        if (syncRecipeBody.getQttsjb().equalsIgnoreCase("1")) {
            peoples.add(syncRecipeBody.getQttsjbName());
        }

        vo.setPeoples(peoples);

        return vo;
    }


}
